package com.gitee.wsl.ext.collection

import kotlin.jvm.JvmName
import com.gitee.wsl.ext.map.put

/**
 * Like [mapOf] but takes in a [Collection] instead of vararg. Useful if your input
 * into the [Map] is [List.map]ped from another [Collection].
 */
@JvmName("mapFromPairs")
fun <K, V> mapFrom(entries: Collection<Pair<K, V>>): Map<K, V> {
    val map = HashMap<K, V>(entries.size)
    map.putAll(entries)
    require(map.size == entries.size) {
        @Suppress("SimpleRedundantLet") // For debugging purposes if you want to visit the values
        "Duplicate keys: " + entries.groupBy { it.first }.filterValues { it.size > 1 }.let {
            it.keys
        }
    }
    return map
}

/**
 * Like [mapOf] but takes in a [Collection] instead of vararg. Useful if your input
 * into the [Map] is [List.map]ped from another [Collection].
 */
@JvmName("mapFromPairs")
fun <K, V> mapFrom(entries: Sequence<Pair<K, V>>): Map<K, V> {
    val map = HashMap<K, V>()
    var count = 0
    entries.forEach {
        map[it.first] = it.second
        count++
    }
    require(map.size == count) {
        @Suppress("SimpleRedundantLet") // For debugging purposes if you want to visit the values
        "Duplicate keys: " + entries.groupBy { it.first }.filterValues { it.size > 1 }.let {
            it.keys
        }
    }
    return map
}

fun <K, V> Sequence<Pair<K, V>>.toMapStrictly(): Map<K, V> {
    return mapFrom(entries = this)
}

fun <K, V> Collection<Pair<K, V>>.toMapStrictly(): Map<K, V> {
    return mapFrom(entries = this)
}

/**
 * Like [mapOf] but takes in a [Collection] instead of vararg. Useful if your input
 * into the [Map] is [List.map]ped from another [Collection].
 */
@JvmName("mapFromEntries")
fun <K, V> mapFrom(entries: Collection<Map.Entry<K, V>>): Map<K, V> {
    val map = HashMap<K, V>(entries.size)
    entries.forEach(map::put)
    require(map.size == entries.size)
    return map
}
